package gui.freechart;

import function.FunctionTools;
import function.ScalarFunction1d;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/**
 * Klasse zum einfachen Zeichnen von Funktionen mittels JFreeChart.<br>
 * Benutzung:
 * <ol>
 *  <li>Erzeugen einer Instanz von FunctionPlotter (mit Beschriftung)
 *  <li>Hinzufuegen von Funktionen (mittels <code>addFunction<code>)
 *  <li>Zeichnen des Diagramms (mittels <code>plot<code>).
 * </ol>
 *
 * @author Institut fuer Bauinformatik, Leibniz Universitaet Hannover
 */
public class FunctionPlotter {
    
    
    
    /* Funktionen als XYSeries */
    private XYSeriesCollection functions;
    JPanel pan;
    JFrame frame;
    boolean added = false;
    boolean added2 = false;
    /* Beschriftungen */
    private String title, xDesc, yDesc;
    
    /**
     * Erzeugt einen FunctionPlotter, mit Titel "Diagramm" und 
     * Achsenbeschriftungen laut {@link FunctionPlotter#FunctionPlotter(java.lang.String)}.
     */
    public FunctionPlotter() {
        this("Diagramm");
    }

    /**
     * Erzeugt einen FunctionPlotter mit Titel <code>title</code> und 
     * Achsenbeschriftungen "x" und "f(x)".
     * 
     * @param title Titel des Diagramms.
     */
    public FunctionPlotter(String title) {
        this(title, "x", "f(x)");
    }
    
    /**
     * Erzeugt einen FunctionPlotter mit gegebenem Titel und Achsenbeschriftungen.
     * 
     * @param title Titel des Diagramms
     * @param xDesc Beschriftung der x-Achse
     * @param yDesc Beschriftung der y-Achse
     */
    public FunctionPlotter(String title, String xDesc, String yDesc) {
        this.title = title;
        this.xDesc = xDesc;
        this.yDesc = yDesc;
        functions = new XYSeriesCollection();
    }
    
    /**
     * Nimmt die Funktion, die durch die Punkte [x_i, y_i=f(x_i)] definiert ist
     * in das Diagramm auf. In der Legende wird diese Funktion mit <code>name</code>
     * gekennzeichnet.
     * 
     * @param x Feld mit Stuetzstellen x_i
     * @param y Feld mit Funktionswerten y_i an den zugehoerigen Stuetzstellen x_i
     * @param name Name der Funktion
     */
    
    public void addtoPanel(JPanel pan){
    this.pan = pan;
    this.added = true;
    this.added2 = false;
    }
    
    public void addFunction(double[] x, double[] y, String name) {
        if (x.length != y.length)
            throw new IllegalArgumentException("unzulaessig: size of x ("+x.length+") != size of y ("+y.length+")");
        XYSeries xys = new XYSeries(name);
        
        for (int i=0;  i<x.length; i++)
            xys.add(x[i], y[i], false);
        functions.addSeries(xys);
    }

    /**
     * Nimmt die Funktion f in das Diagramm auf. Dazu muss der zu zeichnende
     * Bereich (<code>[xmin,max]</code>) und die Abtastrate <code>dx</code>
     * festgelegt werden. In der Legende wird diese Funktion mit <code>name</code>
     * gekennzeichnet.
     * 
     * @param f     zu zeichnende Funktion
     * @param xmin  linke Grenze des zu zeichnenden Bereichs
     * @param xmax  rechte Grenze des zu zeichnenden Bereichs
     * @param dx    Abtastrate fuer die Stuetzstellen
     * @param name  Name der Funktion
     */
    public void addFunction(ScalarFunction1d f, double xmin, double xmax, double dx, String name) {
        if (xmin >= xmax)
            throw new IllegalArgumentException("unzulaessig: xmin ("+xmin+") >= xmax ("+xmax+")");
        XYSeries xys = new XYSeries(name);
        for (double x=xmin; x<=xmax; x+=dx)
            xys.add(x, f.getValue(x), false);
        functions.addSeries(xys);
    }
    
    /**
     * Ruft {@link #plot(int, int) plot(800,600)} auf.
     */
    public void plot() {
        plot(800,600);
    }
    
    
    /**
     * Ruft {@link #plot(int, int, boolean) plot(800,600, plotPoints)} auf.
     */
    public void plot(boolean plotPoints) {
        plot(800,600, plotPoints);
    }
    
    
    /**
     * Zeichnet ein Diagramm mit allen zuvor (durch <code>addFunction</code>)
     * hinzugefuegten Funktionen in einem Fenster der Groesse <code>xSize x
     * ySize</code>.
     * 
     * @param xSize Pixel in x-Richtung des Fensters
     * @param ySize Pixel in y-Richtung des Fensters
     */
    public void plot(int xSize, int ySize) {
        
        // XY-Linien-Diagramm erstellen
        JFreeChart chart = ChartFactory.createXYLineChart(title, xDesc, yDesc, functions, PlotOrientation.VERTICAL, true, true, false);
        
        // Fuer Modifikationen am Diagramm
        XYPlot plot = chart.getXYPlot();
        plot.setOrientation(PlotOrientation.HORIZONTAL);
        
        // Renderer verwenden, der Shapes und Linien zeichnen kann.
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        for (int i=0; i<plot.getSeriesCount(); i++) {
            // Linien zeichnen (false fuer nicht zeichnen)
            renderer.setSeriesLinesVisible(i, true);
        }
        // Renderer uebernehmen
        plot.setRenderer(renderer);

        // Fenster fuer die Darstellung
        ChartPanel f = new ChartPanel( chart);
        
if(!added){
                //f.setSize(xSize,ySize);
      //  f.setVisible(true);
}
else{
    if(added&& !added2) {
 
        f.setSize(ySize, ySize);
        pan.add(f);
        pan.validate();
        
    }  
    if(added2) {
//         f.setSize(xSize,ySize);
//          f.setVisible(true);
//          f.setVisible(false);
        frame.add(f);
    }  
}

        
    }
    
    
    /**
     * Zeichnet ein Diagramm mit allen zuvor (durch <code>addFunction</code>)
     * hinzugefuegten Funktionen in einem Fenster der Groesse <code>xSize x
     * ySize</code>.
     * 
     * @param xSize Pixel in x-Richtung des Fensters
     * @param ySize Pixel in y-Richtung des Fensters
     */
    public void plot(int xSize, int ySize, boolean plotPoints) {
        
        // XY-Linien-Diagramm erstellen
        JFreeChart chart = ChartFactory.createXYLineChart(title, xDesc, yDesc, functions, PlotOrientation.VERTICAL, true, true, false);
        
        // Fuer Modifikationen am Diagramm
        XYPlot plot = chart.getXYPlot();
        
        // Renderer verwenden, der Shapes und Linien zeichnen kann.
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        for (int i=0; i<plot.getSeriesCount(); i++) {
            // Linien zeichnen (false fuer nicht zeichnen)
            renderer.setSeriesLinesVisible(i, true);
            renderer.setSeriesShapesVisible(i, plotPoints);
        }
        // Renderer uebernehmen
        plot.setRenderer(renderer);

        // Fenster fuer die Darstellung
        ChartFrame f = new ChartFrame("Vis", chart);
        f.setSize(xSize,ySize);
        f.setVisible(true);
    }
    
    
    /** Spielwiese... */
    public static void main(String[] args) {
        
        // Stuetzstellen
        double[] x = new double[] {
            -3.0,-2.0, 1.3, 4.6, 17.5
        };
        // Funktionswerte
        double[] y = new double[] {
            10., 10., 11.2, 12.8, 13.0
        };
        
        ScalarFunction1d sin = FunctionTools.getSinus();
        
        FunctionPlotter plotter = new FunctionPlotter();
//        plotter.addtoFrame(frame);
        
        
        // Zeichnen von f(x_i) = y_i
//        plotter.addFunction(x, y, "f");
        // Sinus zeichnen (mit ScalarFunction1d)
//        plotter.addFunction(sin, 0.,10., 0.1, "Sinus");
        // e(x) zeichnen (mit anonymer innerer Klasse)
        plotter.addFunction(new ScalarFunction1d() {

            @Override
            public double getValue(double x) {
                return Math.exp(x);
            }
        }, 0, 6., 1, "e(x)");
        
        JFrame frame = new JFrame();
        frame.setSize(600, 600);
        frame.setVisible(true);
        JPanel pan = new JPanel();
        plotter.addtoFrame(frame);
//        frame.add(pan);
//        plotter.addtoPanel(pan);
        
        plotter.plot(400,400);
       frame.repaint();
      // frame.setSize(501, 501);
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private void addtoFrame(JFrame frame) {
        added = true;
        added2 = true;
        this.frame = frame;
    }
}
